const {
    values,
    reject
} = require("lodash");

const PENDING = 'pending';
const FULFILLED = 'fulfiled';
const REJECTED = 'rejected';


class MyPromise {
    constructor(executor) {

        try {
            // 初始化，执行器
            executor(this.resolve, this.reject);
        } catch (e) {
            this.reject(e);
        }

    }

    status = PENDING;
    value = undefined;
    reason = undefined;

    // 处理异步判断逻辑 successCallBack failCallBack
    // []多个then调用逻辑
    successCallBack = [];
    failCallBack = [];

    // * resolve和reject方法定义的时候用箭头函数,为了让函数的内部this指向这个类的实例对象，就是这个Promise对象
    resolve = (value) => {

        if (this.status != PENDING) return;

        this.value = value;
        this.status = FULFILLED;

        // // 异步时情况处理（注意：非异步的判空处理）
        // this.successCallBack && this.successCallBack(this.value);
        while (this.successCallBack.length) this.successCallBack.shift()()


    }


    reject = (reason) => {

        if (this.status != PENDING) return;
        console.log(reason);

        this.reason = reason;
        this.status = REJECTED;

        // // 异步时情况处理（注意：非异步的判空处理）
        // this.failCallBack && this.failCallBack(reason);

        while (this.failCallBack.length) this.failCallBack.shift()()
    }


    then(successCallBack, failCallBack) {

        // 参数可选
        successCallBack = successCallBack ? successCallBack : value => value;
        // 参数可选
        failCallBack = failCallBack ? failCallBack : reason => {
            throw reason
        };

        // 声明新的promise，给then回传，使then能够链式调用
        let promise2 = new MyPromise((resolve, reject) => {

            if (this.status === FULFILLED) {
                setTimeout(() => {
                    try {
                        // 判断then的回调，是否为Promise，如果是Promise，需要等成功的回调
                        let resCallBack = successCallBack(this.value);
                        resolvePromise(promise2, resCallBack, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }

                }, 0);

            } else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        // 判断then的回调，是否为Promise，如果是Promise，需要等成功的回调
                        let resCallBack = failCallBack(this.reason);
                        resolvePromise(promise2, resCallBack, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }

                }, 0);

            } else {

                // 如果走异步，暂时先缓存起来成功失败的回调

                this.successCallBack.push(() => {
                    setTimeout(() => {
                        try {
                            // 判断then的回调，是否为Promise，如果是Promise，需要等成功的回调
                            let resCallBack = successCallBack(this.value);
                            resolvePromise(promise2, resCallBack, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }

                    }, 0)
                });
                this.failCallBack.push(() => {
                    setTimeout(() => {
                        try {
                            // 判断then的回调，是否为Promise，如果是Promise，需要等成功的回调
                            let resCallBack = failCallBack(this.reason);
                            resolvePromise(promise2, resCallBack, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }

                    }, 0)
                });

            }
        });

        return promise2;
    }

    finally(callback) {
        return this.then(value => {
            return MyPromise.resolve(callback()).then(() => value);
        }, reason => {
            return MyPromise.resolve(callback()).then(() => {
                throw reason
            })
        })
    } 
    
    catch (failCallback) {
        return this.then(undefined, failCallback)
    }

    static all(array) {
        let result = [];
        let index = 0;
        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                result[key] = value;
                index++;
                if (index === array.length) {
                    resolve(result);
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof MyPromise) {
                    // promise 对象
                    current.then(value => addData(i, value), reason => reject(reason))
                } else {
                    // 普通值
                    addData(i, array[i]);
                }
            }
        })
    }

    static resolve(value) {
        if (value instanceof MyPromise) return value;
        return new MyPromise(resolve => resolve(value));
    }

}


function resolvePromise(promise2, resCallBack, resolve, reject) {
    if (promise2 === resCallBack) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>(调用自己循环引用)'));
    }


    if (resCallBack instanceof MyPromise) {
        resCallBack.then(resolve, reject);
    } else {
        resolve(resCallBack);
    }

}


module.exports = MyPromise;